home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / files / standard file / customputsuffix / customputsuffix.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  11.8 KB  |  334 lines

  1. /*
  2.     File:        CustomPutSuffix.c
  3.  
  4.     Contains:    This demonstrates a CustomPutDialog with an Save button that checks
  5.                 to see if several files (with the name filename+suffix) already exist.
  6.                 a dialog hook procedure is responsible for presenting separate "Replace?"                     dialogs.  When the Save button is hit and, if the user allows the save,
  7.                 the Save action is map to a Cancel action but the reply is marked as good.
  8.  
  9.     Written by: David Hayward    
  10.  
  11.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 7/1/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 5/12/95                        updated project for Metrowerks
  24.                 5/3/93                        first draft
  25. */
  26.  
  27.  
  28. #include <stddef.h>
  29.  
  30. #include <QuickDraw.h>
  31. #include <Memory.h>
  32. #include <Files.h>
  33. #include <Errors.h>
  34. #include <Fonts.h>
  35. #include <Resources.h>
  36. #include <StandardFile.h>
  37. #include <Files.h>
  38. #include <Dialogs.h>
  39. #include <TextUtils.h>
  40.  
  41. #include "InitMac.h"
  42.  
  43.  
  44. /**\
  45. |**| ==============================================================================
  46. |**| DEFINES
  47. |**| ==============================================================================
  48. \**/
  49. #define    outputDlogID        128
  50. #define    outputQuit            1
  51. #define    outputAgain            2
  52.  
  53. #define    replaceDlogID        6045
  54. #define    replaceCancel        1
  55. #define    replaceOK            2
  56.  
  57. #define    SuffixID            128
  58.  
  59.  
  60. /**\
  61. |**| ==============================================================================
  62. |**| TYPEDEFS
  63. |**| ==============================================================================
  64. \**/
  65.  
  66. /*------------------------------------------------------------------------------*\
  67.     myData
  68.  *------------------------------------------------------------------------------*
  69.         the 'myData' structure is passed to CustomPutFile() so that 
  70.         MyDlgHook() can access the list of suffixes and return the results 
  71. \*------------------------------------------------------------------------------*/
  72. typedef struct myData
  73. {
  74.     StandardFileReply        *replyPtr;    /* we also need to pass in the SFR so that */
  75.                                         /* MyDlgHook() knows what user specified in */
  76.                                         /* the CustomPutFile dialog */
  77.     short                    num;        /* the number of entries in the array */
  78.     
  79.     struct
  80.     {                                    /* struct for each suffix to check */
  81.         Str63  suffix;                    /* suffix string to append */
  82.         FSSpec spec;                    /* FSSpec for the file */
  83.         FInfo  info;                    /* returned info and err just in case */
  84.         OSErr  err;                        /* we need this information later */
  85.     }                        files[];    /* variable length array of the above */
  86. } myData, *myDataPtr;
  87.  
  88.  
  89.  
  90. /**\
  91. |**| ==============================================================================
  92. |**| FUNCTION PROTOTYPES
  93. |**| ==============================================================================
  94. \**/
  95. void            AppendStrToStr        ( StringPtr dst, StringPtr src, unsigned char maxDstLen );
  96. void            AppendStrToHdl        ( Handle dst, StringPtr src );
  97. pascal short    MyDlgHook            ( short item, DialogPtr theDialog, void *data );
  98. short            myReplaceAlert        ( myDataPtr dataPtr );
  99. short            outputDlog            ( myDataPtr dataPtr );
  100. void            initializeData        ( myDataPtr *dataPtr, StandardFileReply *replyPtr );
  101. void            main                ( void );
  102.  
  103.  
  104. /*------------------------------------------------------------------------------*\
  105.     AppendStrToStr()
  106.  *------------------------------------------------------------------------------*
  107.         utility function to append one string to another
  108.         this function should be improved to handle errors
  109. \*------------------------------------------------------------------------------*/
  110. void AppendStrToStr ( StringPtr dst, StringPtr src, unsigned char maxDstLen )
  111. {
  112.     short        offset = dst[0]+1;
  113.     short        size   = src[0];
  114.     
  115.     if ( dst[0] + src[0] > maxDstLen)            // make sure were not too big
  116.         size = maxDstLen - dst[0];                // you should return a warning here
  117.     BlockMove( src+1, dst+offset, size);
  118.     dst[0] += size;
  119. }
  120.  
  121.     
  122. /*------------------------------------------------------------------------------*\
  123.     AppendStrToHdl()
  124.  *------------------------------------------------------------------------------*
  125.         utility function to append a string to a handle
  126.         this function should be improved to handle errors
  127. \*------------------------------------------------------------------------------*/
  128. void AppendStrToHdl ( Handle dst, StringPtr src )
  129. {
  130.     short        size = src[0];
  131.     PtrAndHand( src+1, dst, size);
  132. }
  133.  
  134.     
  135. /*------------------------------------------------------------------------------*\
  136.     MyDlgHook()
  137.  *------------------------------------------------------------------------------*
  138.         the dialog hook procedure responsible for presenting my own "Replace?" 
  139.         dialogs when the Save button is hit and, if the user allows the save,
  140.         then map the Save action to a Cancel action but mark the reply as good.
  141. \*------------------------------------------------------------------------------*/
  142. pascal short MyDlgHook ( short item, DialogPtr theDialog, void *data )
  143. {
  144.     long                        refCon;
  145.     short                        r;
  146.  
  147.     refCon = GetWRefCon((WindowPtr)theDialog);            /* get the refCon of the current dialog */
  148.  
  149.     if (refCon == sfMainDialogRefCon)                    /* if its the "Save As…" dialog */
  150.     {
  151.         if (item == sfItemOpenButton)                    /* if user hit Save button */
  152.         {
  153.             r = myReplaceAlert((myDataPtr)data);        /* present my "Replce? dialogs */
  154.             if ( r == replaceCancel )                    /* if user hit a Cancel button */
  155.                 item = sfHookNullEvent;                    /* then do nothing */
  156.             else                                        /* if user hit replace button */
  157.             {                                            /* then user wants to save so...*/
  158.                 item  = sfItemCancelButton;                /* change to Cancel action but */ 
  159.                 ((myDataPtr)data)->replyPtr->sfGood = 1;/* mark reply as good */
  160.             }
  161.         }
  162.     }
  163.     
  164.     return item;
  165. }
  166.  
  167.  
  168. /*------------------------------------------------------------------------------*\
  169.     myReplaceAlert()
  170.  *------------------------------------------------------------------------------*
  171.         this routine, called from MyDlgHook(), presents a "Replce? dialog
  172.         for any filename+suffix that already exist.  If one of these
  173.         dialogs is canceles then this procedure returns 'cancel'
  174. \*------------------------------------------------------------------------------*/
  175. short myReplaceAlert ( myDataPtr dataPtr )
  176. {
  177.     short        i, item;
  178.     OSErr        err;
  179.     FSSpec        spec;
  180.     FInfo        info;
  181.     
  182.     for (i=0; i<dataPtr->num; i++)                        /* loop thru each suffix in dataPtr ... */
  183.     {
  184.         spec = dataPtr->replyPtr->sfFile;                /* spec starts out as the FSSpec (vRefNum, */
  185.                                                         /* parID & name) the user specified in the */
  186.                                                         /* CustomPutFile dialog  */
  187.         
  188.         AppendStrToStr( spec.name,
  189.                         dataPtr->files[i].suffix, 63);    /* append suffix to filename */
  190.  
  191.         err = FSpGetFInfo(&spec, &info);                /* try to get info for this spec */
  192.         
  193.         dataPtr->files[i].spec = spec;                    /* save the spec, info & err for this */
  194.         dataPtr->files[i].info = info;                    /* file in dataPtr just in case we need  */
  195.         dataPtr->files[i].err = err;                    /* this information later */ 
  196.  
  197.         if (err == 0)                                    /* filename+suffix already exists so.. */ 
  198.         {
  199.             ParamText( spec.name, nil, nil, nil);        /* setup param text for "Replace?" alert*/
  200.             item = Alert(replaceDlogID,nil);            /* put up alert */
  201.             if (item == replaceCancel)                    /* if user hit cancel button */
  202.                 return replaceCancel;                    /* then stop and return 'cancel' */
  203.         }
  204.         else if (err == fnfErr)                            /* if filename+suffix doesn't exist */
  205.         {
  206.             /* all you need to do in here is make sure that filename+suffix */
  207.             /* isn't a directory and put up an an alert if it is */
  208.         }
  209.         else                                            /* if some other err was returned ... */
  210.         {
  211.             /* here you need to handle other errors such as 'badNamErr' */
  212.         }
  213.     }
  214.     return replaceOK;
  215. }
  216.  
  217.  
  218. /*------------------------------------------------------------------------------*\
  219.     outputDlog()
  220.  *------------------------------------------------------------------------------*
  221.         output vital stats of the StandardFileReply to an dialog box
  222. \*------------------------------------------------------------------------------*/
  223. short outputDlog ( myDataPtr dataPtr )
  224. {
  225.     DialogPtr    dlg;
  226.     Rect        iRect;
  227.     Handle        iHndl;
  228.     short        iType;
  229.     short        item;
  230.     short        i;
  231.     
  232.     dlg = GetNewDialog(outputDlogID, nil, (WindowPtr)-1);
  233.     
  234.     GetDialogItem( dlg, 3, &iType, &iHndl, &iRect );            /* get handle to static text field */
  235.  
  236.     if (dataPtr->replyPtr->sfGood == 0)                    /* if reply is not good */
  237.         AppendStrToHdl (iHndl, "\pUser canceled.");
  238.     else
  239.     {
  240.         for (i=0; i<dataPtr->num; i++)                    /* loop thru each suffix in dataPtr ... */
  241.         {
  242.             AppendStrToHdl( iHndl, dataPtr->files[i].spec.name);     /* append filename */
  243.             
  244.             if ( dataPtr->files[i].err == 0)            /* if filename+suffix already exists */
  245.                 AppendStrToHdl( iHndl, "\p (exists)");    /* append (exists) */
  246.             else if ( dataPtr->files[i].err != fnfErr)
  247.                 AppendStrToHdl( iHndl, "\p (error)");    /* append (error) */
  248.     
  249.             AppendStrToHdl( iHndl, "\p\r");                /* append CR */
  250.         }
  251.     }
  252.     
  253.     ShowWindow( dlg );
  254.     
  255.     do
  256.     {
  257.         ModalDialog(0,&item);
  258.     } while ( (item != outputAgain) && (item != outputQuit));
  259.     
  260.     DisposeDialog(dlg);
  261.     
  262.     return item;
  263. }
  264.  
  265.  
  266. /*------------------------------------------------------------------------------*\
  267.     initializeData()
  268.  *------------------------------------------------------------------------------*
  269.         initialize data stucture to be passed to CustomPutFile
  270.         this means alocating a pointer of the right size and filling 
  271.         in the suffix strings from the apps resource fork 
  272. \*------------------------------------------------------------------------------*/
  273. void initializeData ( myDataPtr *dataPtr, StandardFileReply *replyPtr )
  274. {
  275.     short    i=0, num=0;
  276.     Str255    temp;
  277.     
  278.     do                                                /* figure out how many suffixes */ 
  279.     {                                                /* are in the apps resource fork */
  280.         GetIndString( temp, SuffixID, num+1);
  281.         num++;
  282.     } while (temp[0] !=0);                            /* if temp[0]==0 then no more */
  283.     num--;                                            /* counted 1 too many so decrement */
  284.     
  285.                                                     /* allocate myDataPtr stucture */
  286.     *dataPtr = (myDataPtr) NewPtrClear ( offsetof(myData,files[num]) );
  287.     
  288.     (**dataPtr).replyPtr = replyPtr;                /* fill in StandardFileReply ptr */ 
  289.     (**dataPtr).num = num;                            /* fill in num of suffixes */ 
  290.  
  291.     for (i=0; i<num; i++)                            /* fill in suffix strings */
  292.            GetIndString( (**dataPtr).files[i].suffix, SuffixID, i+1);
  293. }
  294.  
  295.  
  296. /*------------------------------------------------------------------------------*\
  297.     main()
  298.  *------------------------------------------------------------------------------*
  299.         initialize mamagers and the keep doing 
  300.         CustomPutFile until the user has had enough
  301.         the structure 'dataPtr' is passed to CustomPutFile() so that 
  302.         MyDlgHook() can access the list of suffixes and return the results 
  303. \*------------------------------------------------------------------------------*/
  304. void main ( void )
  305. {
  306.     myDataPtr            dataPtr;
  307.     StandardFileReply    reply;
  308.     Point                where = {-1,-1};            /* center dialog on main screen */
  309.     
  310.     InitToolBox(2);
  311.     
  312.     initializeData (&dataPtr, &reply);
  313.     
  314.     do
  315.     {
  316.         CustomPutFile(    "\pSave files as:",            /* the prompt string */
  317.                         "\pUntitled",                /* the default filename */
  318.                         &reply,                        /* the StandardFileReply structure */
  319.                         0,                            /* the default dialog */
  320.                         where,                        /* position of dialog on screen */
  321.                         NewDlgHookYDProc(MyDlgHook),/* the Dialog Hook procedure */
  322.                         nil,                        /* no modal dialog filterProc */
  323.                         nil,                        /* no activeListPtr */
  324.                         nil,                        /* no activateProc */
  325.                         dataPtr                        /* pass in myDataPtr struct so that */
  326.                       );                            /* dlgHook() can access its contents */
  327.     }                                                            
  328.     while (outputDlog(dataPtr)==outputAgain);        /* repeat until user has had enough */
  329.     
  330.     DisposePtr( (Ptr)dataPtr);
  331. }
  332.  
  333.  
  334.